package rs.udd.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.envers.Audited;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import rs.udd.model.Role.Roles;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Audited
@Entity
@Table(name = "UDD_ADVERTISERS")
public class Advertiser extends AbstractUser implements UserDetails {

	private static final long serialVersionUID = -7197109053609581870L;

	public enum AdvertiserType {
		LEGAL_ENTITY,
		PHYSICAL_ENTITY
	}

	@NotNull
	@Enumerated(EnumType.STRING)
	private AdvertiserType advertiserType;

	@NotBlank
	private String address;

	@NotBlank
	private String phoneNumber;

	@JsonIgnore
	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "advertiser")
	private Set<Advert> adverts = new HashSet<Advert>();

	@JsonIgnore
	@ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, mappedBy = "hiddenAdvertisers")	// initiated by Agent
	private Set<Agent> hiddenByAgents = new HashSet<Agent>();
	
	@JsonIgnore
	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "advertiser")
	private Set<AdvertiserAgentContact> contactedAgents = new HashSet<AdvertiserAgentContact>();

	public Advertiser() {

	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {

		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(1);
		SimpleGrantedAuthority authority = new SimpleGrantedAuthority(Roles.ADVERTISER.name());
		authorities.add(authority);

		return authorities;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return getActive();
	}

	@Override
	public String getUsername() {
		return super.getUsername();
	}

	@Override
	public String getPassword() {
		return super.getPassword();
	}

	public AdvertiserType getAdvertiserType() {
		return advertiserType;
	}

	public void setAdvertiserType(AdvertiserType advertiserType) {
		this.advertiserType = advertiserType;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}

	public Set<Advert> getAdverts() {
		return adverts;
	}

	public void setAdverts(Set<Advert> adverts) {
		this.adverts = adverts;
	}

//	public Set<Agent> getContactedAgents() {
//		return contactedAgents;
//	}
//
//	public void setContactedAgents(Set<Agent> contactedAgents) {
//		this.contactedAgents = contactedAgents;
//	}

	public Set<Agent> getHiddenByAgents() {
		return hiddenByAgents;
	}

	public void setHiddenByAgents(Set<Agent> hiddenByAgents) {
		this.hiddenByAgents = hiddenByAgents;
	}

	public Set<AdvertiserAgentContact> getContactedAgents() {
		return contactedAgents;
	}

	public void setContactedAgents(Set<AdvertiserAgentContact> contactedAgents) {
		this.contactedAgents = contactedAgents;
	}
	
	@Override
	public int hashCode() {

		return new HashCodeBuilder()
				.appendSuper(super.hashCode())
				.append(address)
				.append(phoneNumber)
				.hashCode();
	}

	@Override
	public boolean equals(Object obj) {

		if (obj == null) {
			return false;
		}
		if (obj == this) {
			return true;
		}
		if (obj.getClass() != getClass()) {
			return false;
		}

		final Advertiser otherAdvertiser = (Advertiser) obj;

		return new EqualsBuilder()
				.appendSuper(super.equals(obj))
				.append(address, otherAdvertiser.getAddress())
				.append(phoneNumber, otherAdvertiser.getPhoneNumber())
				.isEquals();
	}

	@Override
	public String toString() {

		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
				.append(super.toString())
				.append("address", address)
				.append("phoneNumber", phoneNumber)
				.toString();
	}

}
